package com.code.soulspring.testspring;

import com.code.soulspring.config.Bean2;
import com.code.soulspring.config.Config;
import com.code.soulspring.config.WebConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;

/**
 * @author lyf
 * @date 2022-09-21 20:41
 */
@Slf4j
public class ApplicationContextTest {

    public static void main(String[] args) throws Exception {
        // testClassPathXmlApplicationContext();

        // testFileSystemXmlApplicationContext();

        // testMockClassPathAndFileSystemXmlApplicationContext();

        // testAnnotationConfigApplicationContext();

        testAnnotationConfigServletWebServerApplicationContext();
    }

    // ⬇️1.最为经典的容器，基于classpath 下 xml 格式的配置文件来创建
    private static void testClassPathXmlApplicationContext() {
        /**
         * ClassPathXmlApplicationContext 是不会自动添加如下后置处理器的；
         * 假如所有bean都在xml中定义了，那就不需要这些后置处理器了；
         * 那假如一些 @Controller @Service 等这些类是没有在 spring xml 中配置的，
         *      又想解析。那就在 spring xml 文件中配置 <context:annotation-config/> ; 就会自动添加如下后处理器了；
         *      多年前一直说的这个配置是扫描路径下那些类；其实就是添加后置处理器，扫描那些类并解析，最终交给beanFactory管理
         */
        // org.springframework.context.annotation.internalConfigurationAnnotationProcessor
        // org.springframework.context.annotation.internalAutowiredAnnotationProcessor
        // org.springframework.context.annotation.internalCommonAnnotationProcessor
        // org.springframework.context.event.internalEventListenerProcessor
        // org.springframework.context.event.internalEventListenerFactory
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // ⬇️2.基于磁盘路径下 xml 格式的配置文件来创建
    private static void testFileSystemXmlApplicationContext() {
        // 可以用绝对路径或者相对路径，使用相对路径的话需要设置idea 的当前工作目录是当前模块
        // FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("E:\\code\\workspace\\soul-framework\\soul-spring\\src\\main\\resources\\bean01.xml");
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\bean01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // ⬇️模拟一下ClassPathXmlApplicationContext和FileSystemXmlApplicationContext底层的一些操作
    private static void testMockClassPathAndFileSystemXmlApplicationContext() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取之前");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println("读取之后");
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions(new ClassPathResource("bean01.xml"));
        // reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\bean01.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    // ⬇️3.较为经典的容器，基于java配置类来创建
    private static void testAnnotationConfigApplicationContext() {
        // 会自动加上5个后处理器;  而对于 ClassPathXmlApplicationContext 是不会自动加这几个后处理器的；
        // org.springframework.context.annotation.internalConfigurationAnnotationProcessor
        // org.springframework.context.annotation.internalAutowiredAnnotationProcessor
        // org.springframework.context.annotation.internalCommonAnnotationProcessor
        // org.springframework.context.event.internalEventListenerProcessor
        // org.springframework.context.event.internalEventListenerFactory
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean2.class).getBean1());
    }

    // ⬇️4.较为经典的容器，基于java配置类来创建，并且还可以用于web环境
    // 模拟了 springboot web项目内嵌Tomcat的工作原理
    private static void testAnnotationConfigServletWebServerApplicationContext() throws IOException {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        // 防止程序终止
        System.in.read();
    }
}


